<?php //strip
/**
 * Class for common plugin's forms.
 *
 * @package odWpPlugin
 * @author Ondrej Donek <ondrejd@gmail.com>
 */
class odWpPlugin_Form extends odWpPlugin_Form_Abstract
{
  /**
   * Constructor - set up the form.
   * 
   * @param string $aName Name of the form.
   * @param string $aDescription Description of the form.
   * @param array $aFields Array with form fields.
   * @param string $aDecorator Optional. Defaultly self::DECORATOR_SIMPLE.
   * @param odWpPlugin_Model_Interface|null $mModel
   * @return void
   */
  public function __construct($aName, $aDescription, 
                              $aFields = array(), 
                              $aDecorator = self::DECORATOR_SIMPLE, 
                              $aModel = null)
  {
    $this->mName = $aName;
    $this->mDescription = $aDescription;
    $this->mFields = $aFields;
    $this->mDecorator = $aDecorator;
    $this->mModel = $aModel;                      
  }
  
  /**
   * Validates current form's values.
   *
   * @param array|null $aValues
   * @return boolean
   */
  public function validate($aValues = null)
  {
    throw new Exception('Not implemented yet!');
  }
  
  /**
   * Validates current form's values.
   *
   * @param string $aValue
   * @param string $aType
   * @return boolean
   */
  public function validateValue($aValue, $aType = self::VALIDATOR_NONE)
  {
    throw new Exception('Not implemented yet!');
  }
  
  /**
   * Renders form into the string and returns it.
   *
   * @return string
   * @todo Add enctype attribute to the form.
   * @todo Allow to set labels of the buttons.
   * @todo Allow to hide reset button.
   * @todo Allow to add another custom button.
   */
  public function render()
  {
    $output = '';
    
    if(!empty($this->mDescription)) {
      $output .= '<div class="form-description">' . $this->mDescription . '</div>' . PHP_EOL;
    }
    
    $output .= '<div class="form-container">' . PHP_EOL;
    $output .= '<form name="' . $this->mName . '" method="' . str_replace('method_', '', $this->mMethod) . '">' . PHP_EOL;
    
    if($this->mDecorator == self::DECORATOR_SIMPLE) {
      $output .= '<dl>' . PHP_EOL;
    }
    else if($this->mDecorator == self::DECORATOR_TABLE) {
      $output .= '<table cellpadding="0" cellspacing="0">' . PHP_EOL;
    }
    
    foreach($this->mFields as $fieldName => $fieldOpts) {
      if($this->mDecorator == self::DECORATOR_TABLE) {
        $output .= '<tr>' . PHP_EOL;
      }
      
      if($this->mDecorator == self::DECORATOR_SIMPLE) {
        $output .= '<dt><label for="' . $fieldName . '-' . $fieldOpts['type'] . '">' . $fieldOpts['label'] . '</label></dt>' . PHP_EOL;
        $output .= '<dd>' . $this->_renderElement($fieldName, $fieldOpts) . '</dd>' . PHP_EOL;
      }
      else if($this->mDecorator == self::DECORATOR_TABLE) {
        $output .= '<th style="text-align: left;"><label for="' . $fieldName . '-' . $fieldOpts['type'] . '">' . $fieldOpts['label'] . '</label></th>' . PHP_EOL;
        $output .= '<td>' . $this->_renderElement($fieldName, $fieldOpts) . '</td>' . PHP_EOL;
      }
      
      if($this->mDecorator == self::DECORATOR_TABLE) {
        $output .= '</tr>' . PHP_EOL;
      }
    }
    
    if($this->mDecorator == self::DECORATOR_SIMPLE) {
      $output .= '</dl>' . PHP_EOL;
    }
    else if($this->mDecorator == self::DECORATOR_TABLE) {
      $output .= '</table>' . PHP_EOL;
    }
    
    $output .= '<input type="reset" value="' . __('Cancel', 'odWpPlugin') . '" class="button-secondary action"/> ';
    $output .= '<input type="submit" value="' . __('Save', 'odWpPlugin') . '" class="button-primary action"/> ';
    
    $output .= '</form>' . PHP_EOL;
    $output .= '</div>' . PHP_EOL;
    
    return $output;
  }
  
  /**
   * Renders and returns form element.
   *
   * @param string $aElmName
   * @param array $aElmOpts
   * @return string
   * @todo For TYPE_SELECT we need to set up the selected value.
   * @todo Check (and finish) TYPE_RADIO.
   * @todo Check (and finish) TYPE_ARRAY.
   */
  protected function _renderElement($aElmName, $aElmOpts = array())
  {
    $output = '';
    
    if(!array_key_exists('disabled', $aElmOpts)) $aElmOpts['disabled'] = false;
    if(!array_key_exists('hidden', $aElmOpts)) $aElmOpts['hidden'] = false;
    if(!array_key_exists('value', $aElmOpts)) $aElmOpts['value'] = $this->getValue($aElmName);
    
    switch($aElmOpts['type']) {
      case self::TYPE_HIDDEN:
      case self::TYPE_TEXT:
      case self::TYPE_PASSWORD:
        $output .= '<input type="' . str_replace('type_', '', $aElmOpts['type']) . '" name="' . $aElmName . '" value="' .
            $aElmOpts['value'] . '"' . 
            (($aElmOpts['disabled'] === true) ? ' disabled="disabled" class="disabled"' : '') . 
            (($aElmOpts['hidden'] === true) ? ' hidden="hidden"' : '') . 
                ' id="' . $aElmName . '-input"/>' . PHP_EOL;
        break;
      
      case self::TYPE_TEXTAREA:
        $output .= '<textarea name="' . $aElmName . '"' . 
            (($aElmOpts['disabled'] === true) ? ' disabled="disabled" class="disabled"' : '') . 
            (($aElmOpts['hidden'] === true) ? ' hidden="hidden"' : '') . 
            ' id="' . $aElmName . '-textarea">' . $aElmOpts['value'] . '</textarea>' . PHP_EOL;
        break;
      
      case self::TYPE_SELECT:
        $options = odWpPlugin_Form::_renderElementOption($aElmOpts['options']);
        $output .= '<select name="' . $aElmName . '"' . 
            (($aElmOpts['disabled'] === true) ? ' disabled="disabled" class="disabled"' : '') . 
            (($aElmOpts['hidden'] === true) ? ' hidden="hidden"' : '') . 
                ' id="' . $aElmName . '-select">' . $options . '</select>' . PHP_EOL;
        break;
      
      case self::TYPE_CHECKBOX:
        $output .= '<input type="checkbox" name="' . $aElmName . '" ';
        if($aElmOpts['value'] === true || $aElmOpts['value'] == 'on') {
          $output .= 'checked="checked"';
        }
        $output .= ' ' . (($aElmOpts['disabled'] === true) ? ' disabled="disabled" class="disabled"' : '') . 
            (($aElmOpts['hidden'] === true) ? ' hidden="hidden"' : '') . 
            ' id="' . $aElmName . '-input"/>' . PHP_EOL;
        break;
      
      case self::TYPE_RADIO:
        $output .= '<input type="radio" name="' . $aElmName . '" ';
        if($aElmOpts['value'] === true) {
          $output .= 'selected="selected"';
        }
        $output .= ' ' . (($aElmOpts['disabled'] === true) ? ' disabled="disabled" class="disabled"' : '') .
            (($aElmOpts['hidden'] === true) ? ' hidden="hidden"' : '') . 
            ' id="' . $aElmName . '-input"/>' . PHP_EOL;
        break;

      case self::TYPE_TINYMCE:
        $output .= '<script type="text/javascript" src="' . get_bloginfo('home') . '/wp-includes/js/tinymce/tiny_mce.js"></script>' . PHP_EOL;
        $output .= '<textarea name="' . $aElmName . '"' . 
            (($aElmOpts['disabled'] === true) ? ' disabled="disabled" class="disabled"' : '') . 
            (($aElmOpts['hidden'] === true) ? ' hidden="hidden"' : '') . 
            ' id="' . $aElmName . '-textarea">' . $aElmOpts['value'] . '</textarea>' . PHP_EOL;
        $output .= '<script type="text/javascript">' . PHP_EOL;
        $output .= 'tinyMCE.init({ theme : "advanced", mode : "exact", elements : "' . $aElmName . '-textarea" });' . PHP_EOL;
        $output .= '</script>' . PHP_EOL;
        break;
      
      case self::TYPE_ARRAY:
        $values = $this->getValue($aElmName);
        $values = (empty($values)) 
            ? array()
            : ((is_string($values)) ? unserialize($values) : $values);
        
        foreach($aElmOpts['array_desc'] as $key => $opts) {
          $elm_name = $aElmName . '_' . $key;
          $opts['value'] = (array_key_exists($key, $values)) ? $values[$key] : false;
          
          if($opts['type'] == self::TYPE_CHECKBOX) {
            $output .= '<span>' . $this->_renderElement($elm_name, $opts) . '&nbsp;';
            $output .= '<label for="' . $elm_name . '">' . $opts['label'] . '</label>&nbsp;&nbsp;</span>' . PHP_EOL;
          } else {
            $output .= '<label for="' . $elm_name . '">' . $opts['label'] . '</label>&nbsp;' . PHP_EOL;
            $output .= $this->_renderElement($elm_name, $opts);
          }
        }
        break;
    }
    
    if(array_key_exists('description', $aElmOpts)) {
      $output .= ' <span class="elmDescription">' . $aElmOpts['description'] . '</span>' . PHP_EOL;
    }
    
    return $output;
  }
  
  /**
   * Renders options for SELECT element. Array should be in form such this:
   * 
   * <code>
   * <?php
   * $options = array(
   *   0 => array('ID' => 1, 'title' => 'Some title'),
   *   1 => array('ID' => 2, 'title' => 'Some title', 'children' => array(
   *     0 => array('ID' => 4, 'title' => 'Some title', 'children' => array(
   *       0 => array('ID' => 7, 'title' => 'Some title', 'children' => array(
   *         ...
   *       ))
   *     )),
   *     1 => array('ID' => 5, 'title' => 'Some title'),
   *     2 => array('ID' => 6, 'title' => 'Some title'),
   *     ...
   *   )),
   *   2 => array('ID' => 3, 'title' => 'Some title'),
   *   ...
   * );
   * ?>
   * </code>
   *
   * @param array $aOptions
   * @return string
   */
  public static function _renderElementOption($aOptions = null)
  {
    if(!is_array($aOptions)) {
      return '';
    }
    
    $output = '';
    
    foreach($aOptions as $option) {
      if(is_array($option)) {
        $hasChildren = false;
        
        if(array_key_exists('children', $option)) 
          if(is_array($option['children']) && count($option['children']) > 0) 
            $hasChildren = true;
        
        if($hasChildren === true) {
          $children = self::_renderElementOption($option['children']);
          $output .= '<option value="' . $option['ID'] . '">' . $option['title'] . '</option>' . PHP_EOL;
          $output .= '<optgroup label="' . $option['title'] . '">' . $children . '</optgroup>' . PHP_EOL;
        } else {
          $output .= '<option value="' . $option['ID'] . '">' . $option['title'] . '</option>' . PHP_EOL;
        }
      }
    }
    
    return $output;
  }
  
} // End of odWpPlugin_Form
